#include "os.h"
#include <nuclei_sdk_soc.h>

/* 1000 ms */
#define RVOS_TICK_PER_SECOND 1
#define SYSTICK_TICK_CONST	(SOC_TIMER_FREQ / RVOS_TICK_PER_SECOND)
#define configKERNEL_INTERRUPT_PRIORITY         0

extern void schedule(void);

static uint32_t _tick = 0;

/* load timer interval(in ticks) for next timer interrupt.*/
void timer_load(int interval)
{
	SysTick_Reload(interval);
}

void mtimer_init(void)
{
    uint64_t ticks = SYSTICK_TICK_CONST;
    SysTick_Config(ticks);
    ECLIC_DisableIRQ(SysTimer_IRQn);
    ECLIC_SetLevelIRQ(SysTimer_IRQn, configKERNEL_INTERRUPT_PRIORITY);

	/*
     * mcu gd32vf103 Each interrupt can be configured with vectored interrupt or non-vectored interrupt.
	 * For non-vector interrupts, the interrupt function entry is irq_entry. When processing the interrupt,
	 * SAVE_CONTEXT and SAVE_CSR_CONTEXT will be executed first to save the context and csr registers.
	 * After the rvos timer interrupt is triggered, we want to save the task directly to the context information,
	 * so the non-vector interrupt mode cannot be used for the timer interrupt, but the vector interrupt is used.
	 *
	 * In the vector processing mode, because the processor does not save the context before jumping into the
	 * interrupt service routine, in theory, the interrupt service routine function itself cannot make sub-function
	 * calls (that is, it must be a Leaf Function).
	 * If the interrupt service routine function accidentally calls other sub-functions (not Leaf Function),
	 * it will cause a function error if it is not handled. In order to avoid this accidental error situation,
	 * as long as the special __attribute__ ((interrupt)) is used to modify the interrupt service routine function,
	 * then the compiler will automatically make a judgment. When function, it will automatically insert a piece of code to save the context.
	 *
	 * In general, for the vector processing mode, we need to write an interrupt processing function in C language,
	 * and it must be modified with __attribute__ ((interrupt)). But when this function is called, there will be a stack operation first.
	 * When we need it, the first thing to call this function is to save the task until morning and afternoon, which conflicts with our needs.
 	 *
	 * So we use the vector processing mode here, but do not use the __attribute__ ((interrupt)) modification.
     */

    ECLIC_SetShvIRQ(SysTimer_IRQn, ECLIC_VECTOR_INTERRUPT);
    ECLIC_EnableIRQ(SysTimer_IRQn);
	__enable_irq();
}

void timer_handler() 
{
	_tick++;

	timer_load(SYSTICK_TICK_CONST);

	schedule();
}
